This page last changed on Nov 30, 2004 by jcarreira.

[本文档内容与模版内容重复, 不做翻译]

Overview

In WebWork 2, the UI tags wrap generic HTML controls while providing tight integration with the core framework. The tags have been designed to minimize the amount of logic in compiled code and delegate the actual rendering of HTML to a template system. The UI tags attempt to cover the most common scenarios, while providing a Component Tag for creating custom components. The UI tags also provide built-in support for displaying inline error messages.

Template System

WebWork 2 uses the Velocity template system to render the actual HTML output for all UI tags. A default implementation of all templates has been included with the core distribution allowing users to use WebWork's UI tags "out of the box". Templates can be edited individually or replaced entirely allowing for complete customization of the resulting HTML output. In addition, the default template can be overridden on a per tag basis allowing for a very fine level of control. The default templates are located in the webwork-2.0.jar file under /decorators/xhtml.

Update (2003-11-13): It is now found in /template/xhtml

Note: This is going to change with the theme support that was added.

The AbstractUI class is the base class that other UI tags extend. It provides a set of attributes that are common across UI components. There are 3 attributes that determine which template is rendered:
  • templateDir (defaults to webwork.ui.templateDir - /template/)
  • theme (defaults to webwork.ui.theme - xhtml)
  • templateName (default is tag dependent, subclasses must implement getDefaultTemplate() to provide this)

These 3 attributes combine to determine the location of the template: templateDir + theme + templateName. For example, the default template for the select tag is "/template/xhtml/select.vm". Any one of these attributes can be overridden by the user at run time.

The AbstractUI class is responsible for loading the correct template. As part of the doStartTag() method, a VelocityContext object is created with the following items:

  • tag - a reference to the tag object
  • stack - the ValueStack
  • ognl - a reference to the utility class OgnlTool
  • req - a reference to the HttpServletRequest object

These variables can be accessed in the template by using $TAG_NAME where TAG_NAME is one of tag, stack, ognl or req. The template file is then processed.

Template support for CSS

The default templates provided with WebWork define two properties for use with CSS. The first property, 'label', is applied to text specified in a label attribute in a JspTag. The second property, 'errorMessage', is applied when displaying inline error messages. Many developers need to highlight error messages more prominently by using an alternative color. The code block below can be used in an external stylesheet or in a style element to display error messages in red.
.errorMessage {
    color: red;
}

Note: A default stylesheet is not provided with the core distribution. Users are encouraged to define their own stylesheet using the properties WebWork exposes or modify the supplied templates to work with an existing stylesheet.

Validation

Validation and error handling are an integrated part of the core framework. The UI tags extend this by providing built-in support for displaying inline error messages. To use this functionality, just have your actions implement the ValidationAware interface or extend the ActionSupport class. The ActionSupport class provides a default implementation of ValidationAware and also provides support for internationalization. UI tags that support displaying error messages include: Component Tag, Password Tag, Radio Tag, Select Tag, Textarea Tag and Textfield Tag.

A very simple example of validation is included below. The key point to understand is how to add an error message to a specific control. WebWork will display the specified message inline with the form element.

Users are encouraged to take a closer look at the validation framework in XWork. It provides a number of benefits including separating validation code from your action class, declaring rules based on field type, and providing different validation rules for each action alias. The XWork validation framework is based on an interceptor allowing validation to be added or removed from an action with a quick configuration file change. For more information see the XW:Validation Framework.

Example: Displaying field errors

Action class:

import com.opensymphony.xwork.ActionSupport;

public class RegisterEmail extends ActionSupport {

    private String email;

    public void setEmail(String email) {
        this.email = email;
    }

    public String getEmail() {
        return email;
    }

    public String execute() throws Exception {
        if (email == null || email.equals("")) {
            // the first parameter is the name attribute
            //   specified in <ui:textfield>
            // the second parameter is the error message
            //   to display
            addFieldError("email", "Email address is required.");
        }

        if (hasErrors()) {
            return ERROR;
        } else {
            return SUCCESS;
        }
    }

}

Jsp page:

<%@ taglib uri="webwork" prefix="ui" %>

<html>
<head><title>validation example</title></head>
<style type="text/css">
.errorMessage {
    color: red;
}
</style>
<body>

<form name="frmRegister" action="RegisterEmail.action" method="POST">
    <table>
        <ui:textfield label="Email" name="email" value="" size="50" />
        <tr>
            <td colspan="2">
                <input type="submit" name="submit" value="Register" />
            </td>
        </tr>
    </table>
</form>

</body>
</html>

HTML output (before submitting):

<html>
<head><title>validation example</title></head>
<style type="text/css">
.errorMessage {
    color: red;
}
</style>
<body>

<form name="frmRegister" method="POST" action="RegisterEmail.action">
    <table>
        <tr>
  <td align="right" valign="top"><span class="label">Email:</span></td>
  <td>
<input type="text" name="email" value="" size="50"/>
  </td>
</tr>
        <tr>
            <td colspan="2">
                <input type="submit" name="submit" value="Register" />
            </td>
        </tr>
    </table>
</form>

</body>
</html>

HTML output (after submitting):

<html>
<head><title>validation example</title></head>
<style type="text/css">
.errorMessage {
    color: red;
}
</style>
<body>

<form name="frmRegister" method="POST" action="RegisterEmail.action">
    <table>
            <tr>
    <td colspan="2"><span class="errorMessage">
              Email address is required.
        </span></td>
  </tr>
  <tr>
  <td align="right" valign="top"><span class="label">Email:</span></td>
  <td>
<input type="text" name="email" value="" size="50"/>
  </td>
</tr>

        <tr>
            <td colspan="2">
                <input type="submit" name="submit" value="Register" />
            </td>
        </tr>
    </table>
</form>

</body>
</html>

Example: Displaying action errors

Add the following to the JSP file above the form tag:

<ww:if test="hasErrors()">
<p><span class="errorMessage">
<ww:if test="hasActionErrors()">
  <b>Errors:</b><br>
  <ul>
  <ww:iterator value="actionErrors">
    <li><ww:property/></li>
  </ww:iterator>
  </ul>
</ww:if><ww:else>
  <b>Please fix the errors marked in red to continue</b>
</ww:else>
</span></p>
</ww:if>

This will display any action errors that may have occured.

Creating Custom Components

At first glance the component tag doesn't look that impressive. The ability to specify a single template and use a number of predetermined attributes looks rather lacking. But the supplied tag offers a number of benefits to developers.

Before diving right into the custom component, first I will identify some advantages to using the component tag to create your components. Then I will detail the two types of error messages in WebWork 2 and how our custom component (for displaying one of these types) fits into the equation. Finally, I will present a sample Action class, Jsp file and template file for our component. When we are finished, you will be able to incorporate the new component into your application.

Why use the component tag?

  • removes the need to develop your own Jsp tag library
  • provides integrated support for accessing the ValueStack
  • leverages XWork's support for internationalization, localization and error handling
  • faster prototyping using templates (editable text files) instead of compiled code
  • re-use and combine existing templates

More on error message support:

In WebWork 2, there are two types of error messages: field error messages and action error messages. Field error messages are used to indicate a problem with a specific control and are displayed inline with the control. A number of tags provide built-in support for displaying these types of messages. Action error messages on the other hand, indicate a problem with executing an action. Many things can go wrong in a web application, especially an application that relies on external resources such as a database, remote web service, or other resource that might not be accessible during the execution of an action. Handling an error gracefully and presenting the user with a useful message can often be the difference in a positive user/customer experience and a bad one.

When these types of errors occur, it is more appropriate to display these messages separate from individual controls on the form. In the example below, we will create a custom component that can be used to display action error messages in a bulletted list. This component can then be used on all your forms to display these error messages.

The action class below was created to handle a promotion on the website: a free e-certificate. It will try to email the certificate, but an exception will be thrown.

Action class:

package example;

import com.opensymphony.xwork.ActionSupport;

public class AddUser extends ActionSupport {

    private String fullname;
    private String email;

    public String execute() throws Exception {
        // we are ignoring field validation in this example

        try {
            MailUtil.sendCertificate(email, fullname);
        } catch (Exception ex) {
            // there was a problem sending the email
            // in a real application, we would also
            // log the exception
            addActionError("We are experiencing a technical problem and have contacted our support staff. " +
                           "Please try again later.");
        }

        if (hasErrors()) {
            return ERROR;
        } else {
            return SUCCESS;
        }
    }

    public String getFullname() {
        return fullname;
    }

    public void setFullname(String fullname) {
        this.fullname = fullname;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

}

Jsp page:

<%@ taglib uri="webwork" prefix="ui" %>

<html>
<head><title>custom component example</title></head>
<style type="text/css">
.errorMessage {
    color: red;
}
</style>
<body>

<ui:form action="AddUser.action" method="POST">
<table>
    <ui:component template="action-errors.vm" />
    <ui:textfield label="Full Name" name="fullname" />
    <ui:textfield label="Email" name="email" />
    <ui:submit name="submit" value="Send me a free E-Certificate!" />
</table>
</ui:form>

</body>
</html>

HTML output (before submitting):

<html>
<head><title>custom component example</title></head>
<style type="text/css">
.errorMessage {
    color: red;
}
</style>
<body>

<form  action="AddUser.action" method="POST" />

<table>
    

    <tr>
  <td align="right" valign="top"><span class="label">Full Name:</span></td>
  <td>
<input type="text" name="fullname" value="" />
  </td>
</tr>
    <tr>
  <td align="right" valign="top"><span class="label">Email:</span></td>
  <td>
<input type="text" name="email" value="" />
  </td>
</tr>
    
<tr>
  <td colspan="2">
    <div align="right">
      <input type="submit" name="submit" value="Send me a free E-Certificate!"/>
    </div>
  </td>
</tr>


</table>
</form>

</body>
</html>

The template below will loop through any action errors and display them to the user in a bulletted list.

Template (action-errors.vm)
#set ($actionErrors = $stack.findValue("actionErrors"))

#if ($actionErrors)
<tr>
    <td colspan="2">
        <span class="errorMessage">The following errors occurred:</span>
        <ul>
            #foreach ($actionError in $actionErrors)
            <li><span class="errorMessage">$actionError</span></li>
            #end
        </ul>
    </td>
</tr>
#end

HTML output (after submitting):

<html>
<head><title>custom component example</title></head>
<style type="text/css">
.errorMessage {
    color: red;
}
</style>
<body>

<form  action="AddUser.action" method="POST" />

<table>
    
<tr>
    <td colspan="2">
        <span class="errorMessage">The following errors occurred:</span>
        <ul>
            <li class="errorMessage">
                We are experiencing a technical problem and have contacted our 
                support staff. Please try again later.
            </li>
        </ul>
    </td>
</tr>

    <tr>
  <td align="right" valign="top"><span class="label">Full Name:</span></td>
  <td>
<input type="text" name="fullname" value="Sample User" />
  </td>
</tr>
    <tr>
  <td align="right" valign="top"><span class="label">Email:</span></td>
  <td>
<input type="text" name="email" value="user@example.com" />
  </td>
</tr>
    
<tr>
  <td colspan="2">
    <div align="right">
      <input type="submit" name="submit" value="Send me a free E-Certificate!"/>
    </div>
  </td>
</tr>


</table>
</form>

</body>
</html>

Changes from WebWork 1

TODO

Document generated by Confluence on Dec 14, 2004 16:37